﻿using System.Collections.Generic;
using System.Net.Sockets;

namespace JPR.Common.Objects
{
	public class BufferManager
	{
		private readonly byte[] _buffer;
		private readonly int _bufferSize;
		private readonly Stack<int> _freeIndexPool;
		private readonly int _numBuffers;
		private int _currentIndex;

		public BufferManager() : this(100, 16384)
		{
		}

		public BufferManager(int totalBuffers, int bufferSize)
		{
			_numBuffers = totalBuffers;
			_currentIndex = 0;
			_bufferSize = bufferSize;
			_freeIndexPool = new Stack<int>();
			_buffer = new byte[_numBuffers*_bufferSize];
		}

		public bool SetBuffer(SocketAsyncEventArgs args)
		{
			lock (_buffer)
			{
				return SetBufferUnsafe(args);
			}
		}

		private bool SetBufferUnsafe(SocketAsyncEventArgs args)
		{
			if (_freeIndexPool.Count > 0)
			{
				args.SetBuffer(_buffer, _freeIndexPool.Pop(), _bufferSize);
			}
			else
			{
				if ((_numBuffers*_bufferSize - _bufferSize) < _currentIndex)
				{
					return false;
				}
				args.SetBuffer(_buffer, _currentIndex, _bufferSize);
				_currentIndex += _bufferSize;
			}
			return true;
		}

		public void FreeBuffer(SocketAsyncEventArgs args)
		{
			lock (_buffer)
			{
				FreeBufferUnsafe(args);
			}
		}

		private void FreeBufferUnsafe(SocketAsyncEventArgs args)
		{
			_freeIndexPool.Push(args.Offset);
			args.SetBuffer(null, 0, 0);
		}
	}
}